﻿using System;
using NHibernate.Hql.Ast;
using NHibernate.Linq;
using NHibernate.Linq.Functions;

namespace Framework.Repositories.NHibernate
{
    /// <summary>
    /// Represents the HQL generator for the Equals method on primitive CLR types.
    /// </summary>
    /// <remarks>The HQL generator in NHibernate 3 only supports the Equals method
    /// on the <see cref="System.String"/> type, for other primitive CLR types, it
    /// is not supported. This class is for solving this issue. For more information
    /// please refer to http://www.primordialcode.com/blog/post/nhibernate-3-extending-linq-provider-fix-notsupportedexception.
    /// </remarks>
    public class ExtendedEqualsGenerator : BaseHqlGeneratorForMethod
    {
        #region Ctor
        /// <summary>
        /// Initializes a new instance of <c>ExtendedEqualsGenerator</c> class.
        /// </summary>
        public ExtendedEqualsGenerator()
        {
            SupportedMethods = new[] {
                ReflectionHelper.GetMethodDefinition<Byte>(x => x.Equals((Byte)0)),
                ReflectionHelper.GetMethodDefinition<SByte>(x => x.Equals((SByte)0)),
                ReflectionHelper.GetMethodDefinition<Int16>(x => x.Equals((Int16)0)),
                ReflectionHelper.GetMethodDefinition<Int32>(x => x.Equals((Int32)0)),
                ReflectionHelper.GetMethodDefinition<Int64>(x => x.Equals((Int64)0)),
                ReflectionHelper.GetMethodDefinition<UInt16>(x => x.Equals((UInt16)0)),
                ReflectionHelper.GetMethodDefinition<UInt32>(x => x.Equals((UInt32)0)),
                ReflectionHelper.GetMethodDefinition<UInt64>(x => x.Equals((UInt64)0)),
                ReflectionHelper.GetMethodDefinition<Single>(x => x.Equals((Single)0)),
                ReflectionHelper.GetMethodDefinition<Double>(x => x.Equals((Double)0)),
                ReflectionHelper.GetMethodDefinition<Boolean>(x => x.Equals(true)),
                ReflectionHelper.GetMethodDefinition<Char>(x => x.Equals((Char)0)),
                ReflectionHelper.GetMethodDefinition<Decimal>(x => x.Equals((Decimal)0)),
                ReflectionHelper.GetMethodDefinition<Guid>(x => x.Equals(Guid.Empty)),
            };
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Builds the HQL.
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="targetObject">The target object.</param>
        /// <param name="arguments">The arguments.</param>
        /// <param name="treeBuilder">The AST tree builder.</param>
        /// <param name="visitor">The visitor.</param>
        /// <returns>A HQL tree node.</returns>
        public override global::NHibernate.Hql.Ast.HqlTreeNode BuildHql(System.Reflection.MethodInfo method, System.Linq.Expressions.Expression targetObject, System.Collections.ObjectModel.ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, global::NHibernate.Hql.Ast.HqlTreeBuilder treeBuilder, global::NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor)
        {
            return treeBuilder.Equality(
                visitor.Visit(targetObject).AsExpression(),
                visitor.Visit(arguments[0]).AsExpression());
        }
        #endregion
    }
}
